<?php
/**
 * Created by Administrator
 * User: longli
 * VX: isa1589518286
 * Date: 2020/08/12
 * Time: 10:48
 * @link http://www.lmterp.cn
 */

namespace app\common\service\platform;

use ApiConfig;
use app\common\library\Tools;
use app\common\model\AccountSyncLog;
use app\common\model\OrdersTemp;
use app\common\service\channel\BaseChannel;
use app\common\service\orders\OrderService;
use BlibliMerchantClient;
use think\facade\Log;
use TokenRefresh;
use TokenRequest;

require_once \Env::get("root_path") . 'extend/blibli/BlibliMerchantClient.php';

/**
 * Blibli 接口服务, 平台需要提供回调地址授权
 * Class BlibliService
 * @package app\common\service\blibli
 * @link https://seller-api.blibli.com/docs/sections/60/contents/2867?title=introduction
 * @link https://github.com/bliblidotcom
 */
class BlibliService extends BasePlatformService
{
    public static $tokenField = [
        'required' => [ // 必填字段
            [
                'type' => 'text',
                'name' => 'business',
                'field' => 'business',
            ],
            [
                'type' => 'text',
                'name' => 'secret_key',
                'field' => 'secret_key',
            ],
            [
                'type' => 'text',
                'name' => 'api_username',
                'field' => 'api_username',
            ],
            [
                'type' => 'text',
                'name' => 'mta_username',
                'field' => 'mta_username',
            ],
            [
                'type' => 'text',
                'name' => 'mta_password',
                'field' => 'mta_password',
            ],
            [
                'type' => 'text',
                'name' => 'platform_name',
                'field' => 'platform_name',
            ],
            [
                'type' => 'text',
                'name' => 'refresh_token',
                'field' => 'refresh_token',
            ],
        ],
        'option' => [ // 可选字段
            [
                'type' => 'text',
                'name' => 'access_token',
                'field' => 'access_token',
                'readonly' => true,
            ],
        ],
    ];
    /**
     * 发起请求
     * @param string $url 请求地址
     * @param array $params 请求参数
     * @date 2020/08/12
     * @author longli
     * @return mixed
     */
    public function request($url, $params = [])
    {
        Log::info(sprintf("Blili 账号【%d】发起请求，请求参数: 【%s】", $this->getAccountId(), json_encode($params)));
        $account = $this->getAccount();
        $config = new ApiConfig();
        $config->setToken($account->token->access_token); //your API token
        $config->setSecretKey($account->token->secret_key); //your API secret key
        $config->setMtaUsername($account->token->mta_username); //your MTA username
        $config->setBusinessPartnerCode($account->token->business); //your Business Partner Code / Merchant Code
        $config->setPlatformName($account->token->platform_name); //your company name/platform name
        $config->setTimeoutSecond(30); //your request timeout
        $client = new BlibliMerchantClient();

        $response = $client->invokeGet($url, $params, $config);
        return json_decode($response,true);
    }

    /**
     * 同步订单列表
     * @param array $params 请求参数
     * @param bool $replace 是否替换原有的订单
     * @date 2020/08/12
     * @author longli
     * @link https://api.blibli.com/v2/proxy/mta/api/businesspartner/v1/order/orderList
     * @example [
     *  'page_size' => 100,
     *  'start_date' => '2020-08-07',
     *  'end_date' => '2020-08-08',
     *  'status'  => 'FP', // 可选 FP/PF/CR/CX/PU/OS/BP/D/X
     * ]
     */
    public function getOrderList($params = [], $replace = false)
    {
        Log::info(sprintf("Blili 批量同步账号【%d】订单，请求参数: 【%s】", $this->getAccountId(), json_encode($params)));
        $page = 0;
        $args = [
            'page' => $page,
            'size' => !empty($params['page_size']) && $params['page_size'] > 0 ? $params['page_size'] : 100,
            'filterStartDate' => urldecode(!empty($params['start_date']) ? $params['start_date'] : date('Y-m-d')), // urlencode('2020-08-01'),
            'filterEndDate' => urlencode(!empty($params['end_date']) ? $params['end_date'] : date('Y-m-d H:m:s')),
            'sortBy' => 'desc',
            //'status' => !empty($params['status']) ? $params['status'] : 'FP',
        ];
        $url = $this->getBaseUrl() . "/proxy/mta/api/businesspartner/v1/order/orderList";
        $startSyncTime = time();
        $refresh = 0;
        do
        {
            $refreshToken = false;
            $args['page'] = $page;
            $orders = $this->request($url, $args);
            if(empty($orders)) break;
            if(empty($orders['success']))
            {
                if(isset($orders['error']) && $orders['error'] == 'invalid_token')
                {
                    if($refresh++ > 3) break;
                    $refreshToken = true;
                    $this->refreshToken(); // 刷新 token
                    continue;
                }
                Log::info(sprintf("Blili 账号【%d】获取订单失败， 错误信息: 【%s】", $this->getAccountId(), json_encode($orders)));
                break;
            }
            foreach($orders['content'] as $order)
            {
                $order['detail'] = $this->getOrderDetail($order);
                $order['detail']['label_url'] = $this->getLabelByItemNo($order['orderItemNo']);
                $data = [$order['orderItemNo'] => $order];
                if($orderTemp = OrdersTemp::get(['order_no' => $order['orderNo'], 'account_id' => $this->getAccountId()]))
                {
                    $data += $orderTemp->order_info;
                    $replace = true;
                }
                $this->pushOrderToTemp($order['orderNo'], $data, $replace);
            }
            $page++;
        }while($refreshToken || count($orders['content']) == $args['size']);
        // 添加同步订单日志
        AccountSyncLog::addLog($this->getAccountId(), $startSyncTime, time(), $args);
    }

    /**
     * 获取订单详情
     * @param array $order 订单数据
     * @return array
     * @date 2020/08/22
     * @author longli
     */
    protected function getOrderDetail($order = [])
    {
        $url = $this->getBaseUrl() . "/proxy/mta/api/businesspartner/v1/order/orderDetail";
        $args = [
            'orderNo' => $order['orderNo'],
            'orderItemNo' => $order['orderItemNo'],
        ];
        $detail =  $this->request($url, $args);
        $error = 1;
        while($detail === null || !$detail['success'])
        {
            sleep(2);
            $detail = $this->request($url, $args);
            if($error++ > 5)
            {
                Log::info(sprintf("Blili 账号【%d】获取订单详情失败, 订单号：【%s】", $this->getAccountId(), "{$order['orderNo']}-{$order['orderItemNo']}"));
                return [];
            }
        }
        return $detail['value'];
    }

    /**
     * 通过平台产品编号获取面单
     * @param string $orderItemNo 平台产品编号
     * @return string 返回面单在系统中的路径
     * @date 2020/08/22
     * @author longli
     */
    public function getLabelByItemNo($orderItemNo)
    {
        Log::info(sprintf("Blili 账号【%d】获取面单, 产品id:【%s】", $this->getAccountId(), $orderItemNo));
        $url = $this->getBaseUrl() . "/proxy/mta/api/businesspartner/v1/order/downloadShippingLabel";
        $args = ["orderItemId" => $orderItemNo];
        $response = $this->request($url, $args);
        if(!empty($response) && $response['errorCode'] == 'SL-01')
        {
            Log::info(sprintf("Blili 账号【%d】获取面单失败，订单号：【%s】，错误码：【%s】，错误信息：【%s】", $this->getAccountId(), $orderItemNo, $response['errorCode'], $response['errorMessage']));
            return "";
        }

        $error = 1;
        while($response === null || !$response['success'] || empty($response['value']['document']))
        {
            sleep(2);
            $response = $this->request($url, $args);
            if($error++ > 5)
            {
                Log::info(sprintf("Blili 账号【%d】获取面单失败，订单号：【%s】，错误码：【%s】，错误信息：【%s】", $this->getAccountId(), $orderItemNo, $response['errorCode'], $response['errorMessage']));
                return "";
            }
        }
        return BaseChannel::saveLabel(base64_decode($response['value']['document']));
    }

    public function syncOrder(OrdersTemp $ordersTemp)
    {
        $info = [];
        $totalPrice = 0;
        foreach($ordersTemp->order_info as $data)
        {
            $totalPrice += $data['detail']['finalPrice'] * $data['qty'];
            $info[] = [
                "item_id"           => $data['orderItemNo'], // 产品id
                "platform_sku"      => $data['merchantSku'], // sku
                "name"              => $data['productName'], // 产品在平台的名称
                "qty"               => $data['qty'], // 数量
                "price"             => $data['productPrice'], // 产品价格
                "customer_remark"   => $data['detail']['custNote'], // 客户备注
            ];
        }
        $platform = $this->getAccountById($ordersTemp->account_id)->platform;
        $order = [
            "order_no"                  => $ordersTemp->order_no,
            "account_id"                => $ordersTemp->account_id,
            "platform_name"             => $platform->name, // 平台名称
            "order_platform_status"     => $data['orderStatusString'], // 订单在平台的状态
            "buyer_first_name"          => $data['detail']['custName'], // 客户名称
            "buyer_mobile"              => $data['detail']['shippingMobile'], // 手机
            "buyer_country_code"        => $data['detail']['pickupPointCountry'], // 国家编码
            "buyer_district"            => $data['detail']['shippingSubDistrict'], // 街道
            "buyer_city"                => $data['detail']['shippingCity'], // 城市
            "buyer_post_code"           => $data['detail']['shippingZipCode'], // 邮编
            "buyer_address_1"           => $data['detail']['shippingStreetAddress'], // 买家收货地址
            "order_source_create_time"  => $this->parseTimeToDate($data['orderDate']), // 订单在平台生成的时间
            "shipping_method"           => $data['logisticsOptionName'], // 物流方式
            "track_num"                 => $data['detail']['awbNumber'], // 跟踪号
            "track_num_time"            => !empty($data['detail']['awbNumber']) ? Tools::now() : null, // 更新追踪号时间
            "label_url"                 => $data['detail']['label_url'], // 面单
            "weight"                    => $data['detail']['totalWeight'], // 重量
            "order_price"               => $totalPrice,
            "total_price"               => $totalPrice,
            "currency"                  => 'IDR',
            'order_detail'              => $info,
        ];
        return OrderService::getInstance()->addOrder($order);
    }

    /**
     * 刷新 token
     * @date 2020/08/12
     * @author longli
     * @return bool
     * @link https://api.blibli.com/v2/oauth/token
     */
    public function refreshToken()
    {
        Log::info(sprintf("Blili 刷新账号【%d】token", $this->getAccountId()));
        $account = $this->getAccount();
        $url = $this->getBaseUrl() . "/oauth/token";
        $client = new BlibliMerchantClient();

        if(!empty($account->token->refresh_token))
        {
            $request = new TokenRefresh();
            $request->setApiUsername($account->token->api_username); //your API username
            $request->setApiPassword($account->token->secret_key); //your API password
            $request->setPlatformName($account->token->platform_name); //your company name/platform name
            $request->setTimeoutSecond(30); //your request timeout
            $request->setRefreshToken($account->token->refresh_token);

            $response = $client->refreshToken($url, $request);

            if(!Tools::isJson($response, $json)) return false;
            if(isset($json['error']))
            {
                // 刷新 token 失败
                Log::info(sprintf("Blili 刷新 token 失败, 账号【%d】, 错误信息: 【%s】", $this->getAccountId(), $json['error_description']));
                return false;
            }
            if(!empty($json['access_token']))
            {
                $account->token->access_token = $json['access_token'];
                $account->token->refresh_token = $json['refresh_token'];
                $account->save();
            }
        }
        else
        {
            $request = new TokenRequest();
            $request->setApiUsername($account->token->api_username); //your API username
            $request->setApiPassword($account->token->secret_key); //your API password
            $request->setMtaUsername($account->token->mta_username); //your MTA username
            $request->setMtaPassword($account->token->mta_password); //your MTA password
            $request->setPlatformName($account->token->platform_name); //your company name/platform name
            $request->setTimeoutSecond(30); //your request timeout

            $response = $client->getToken($url, $request);

            if(!Tools::isJson($response, $json))
            {
                Log::info(sprintf("Blili 获取 token 失败, 账号【%d】, 错误信息: 【%s】", $this->getAccountId(), $response));
                return false;
            }
            if(!empty($json['access_token']))
            {
                $account->token->access_token = $json['access_token'];
                $account->token->refresh_token = $json['refresh_token'];
                $account->save();
            }
        }
        return true;
    }
}